#include <stdio.h>
#include <math.h>
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
#include "raw_read.h"
#include "audio.h"

class cProgress {
public:
	cProgress() {iWorking=ulDone=ulTotal=0; dPercent=0.0; Set();};

	void Set(unsigned long ulSetDone, unsigned long ulSetTotal) {
		ulDone=ulSetDone;
		ulTotal=ulSetTotal;
		Set();
	}

	void Set() {
		if(ulTotal) dPercent=(100.0*ulDone)/ulTotal;
		else dPercent=0;
		sprintf(szText,"%08u of %08u Samples Written",ulDone,ulTotal);
	}

	int iWorking;
	unsigned long ulDone, ulTotal;
	double dPercent;
	char szText[64], szTitle[128];
};

#define UDM_UPDATE 0x2323

#define PROG_TITLE "SETI PSRFITS Viewer"
#define PROG_VER	"0.3"

#define MIN(A,B)	((A)<(B)? (A):(B))
#define MAX(A,B)	((A)>(B)? (A):(B))

#define CHAN_TO_X(C)	((C)*iChanWidth)
#define SIDE_TO_X(S)	((S)*(iChanWidth>>1))
#define TIME_TO_Y(T)	int((double(T-ulTimeStart)/iTimeZoom)*iTimeHeight)
#define TIME_IN_PLOT(T) (T>=0 && T<iPlotHeight)
#define X_TO_CHAN(X)	((X)/iChanWidth)
#define Y_TO_SAMP(Y)	(((Y)/iTimeHeight)*iTimeZoom)
#define Y_TO_TIME(Y)	(ulTimeStart+Y_TO_SAMP(Y))

/*Globals*/
HWND		hMainDlg, hProgDlg, hTimeScroll;
HMENU		hMainMenu;
HINSTANCE	hInst;
HDC			hdcWnd, hdcMem;
HBITMAP		hBmp;
HPEN		hpBlackPen, hpGreenPen, hpNullPen;
HBRUSH		hbWhiteBrush, hbBlackBrush, hbNullBrush;
HFONT		hfPlotFont;
RECT		rPlot, rScroll, rSample; //rectangles
POINT		pClick, pDrag; //click & drag points

cRawRead rrRawFile;
cRawSample rsSample;
cProgress pProgress;
cVector vFreq;

int iPlotWidth=512, iPlotHeight=512; //plot dimensions
int iChanWidth, iTimeHeight=1, iTimeZoom=1, iMaxZoom=1; //plot options
int iCharWidth=6, iCharHeight=12; //plot text size
unsigned long ulTimeStart=0, ulMaxTimeStart=0; //scroll position

int iSelChan=0; //sample selection
unsigned long ulSelTime=0, ulSelRange=1;

char szFileName[2048], *szBaseName; //opened file name
char szTitle[512], szMessage[1024]; //window title & general use string

char szOpenFileFilter[]=
	{"PSRFITS RAW Files (*.raw)\0" "*.raw;\0"
	 "All Files (*.*)\0" "*.*\0\0"};

char szSaveFileFilter[]=
	{"Text File (*.txt)\0" "*.txt;\0"
	 "All Files (*.*)\0" "*.*\0\0"};
	 
void ErrorMessage(HWND hWnd, int iError) {
	if(!iError) return;
	
	char szMsg[256];

	switch(iError) {
		case ERROR_FILE_NOT_FOUND:		sprintf(szMsg,"File not found"); break;
		case ERROR_PATH_NOT_FOUND:		sprintf(szMsg,"Path not found"); break;
		case ERROR_ACCESS_DENIED:		sprintf(szMsg,"Access denied"); break;
		case ERROR_INVALID_HANDLE:		sprintf(szMsg,"Invalid file handle"); break;
		case ERROR_INVALID_DATA:		sprintf(szMsg,"Invalid data"); break;
		case ERROR_NOT_ENOUGH_MEMORY:	sprintf(szMsg,"Not enough memory"); break;
		case ERROR_OUTOFMEMORY:			sprintf(szMsg,"Out of memory"); break;
		case ERROR_SEEK:				sprintf(szMsg,"Error seeking"); break;
		case ERROR_WRITE_FAULT:			sprintf(szMsg,"Write fault"); break;
		case ERROR_READ_FAULT:			sprintf(szMsg,"Read fault"); break;
		case ERROR_LOCK_VIOLATION:		sprintf(szMsg,"Lock Violation"); break;
		case ERROR_HANDLE_EOF:			sprintf(szMsg,"End of file"); break;
		case ERROR_NEGATIVE_SEEK:		sprintf(szMsg,"Negative Seek"); break;
		case ERROR_BUSY_DRIVE:			sprintf(szMsg,"Drive Busy"); break;
		case ERROR_FILENAME_EXCED_RANGE:sprintf(szMsg,"Filename too long"); break;
		case ERROR_NOACCESS:			sprintf(szMsg,"No Access"); break;
		case ERROR_INVALID_WINDOW_HANDLE: sprintf(szMsg,"Invalid window handle"); break;
		default: sprintf(szMsg,"Error %i (%X)",iError,iError); break;
	}
	sprintf(szMsg+strlen(szMsg),": \"%s\"",szFileName);
	MessageBox(hWnd,szMsg,"Error",MB_OK | MB_ICONERROR); 
	SetLastError(0);
}


/*Audio*/
/*int iSamplesPerSecond=44100;
int iBitsPerSample=16;
int iBytesPerSample=iBitsPerSample/8;
int iPeak8=100, iPeak16=30000;
double dAmp, dMaxAmp;

int iPlaying=0, iPlayChan=0;
unsigned long ulPlayTime=0;


int ClipAudioSample(double dValue) {
	if(iBitsPerSample==16) { //16 bit
		if(dValue>iPeak16) return iPeak16;
		if(dValue<(-1*iPeak16)) return (-1*iPeak16);
		else return int(dValue);
	}
	
	else { //8 bit
		if(dValue>iPeak8) return iPeak8;
		if(dValue<(-1*iPeak8)) return (-1*iPeak8);
		else return int(dValue);
	}
}

DWORD WINAPI PlayAudio(LPVOID iParam) {
	int iNumSamples;
	double dTime=0, dValue;

	if(!rrRawFile.iBlocks) return 0;
	
	if(iBitsPerSample==16) dMaxAmp=iPeak16;
	else dMaxAmp=iPeak8;
	
	dAmp=dMaxAmp;

	char *lprgcBuffer=new char[iSamplesPerSecond*iBytesPerSample];

	while(audioPlaying()) {
		double dToneFreq=128; //tone frequency
		double dCycleTime=1/dToneFreq; //time for one tone cycle
		int iToneSamps=int(iSamplesPerSecond/dToneFreq); //# samples in a tone cycle
		double dSampRatio=(iSamplesPerSecond/rrRawFile.rbBlock.dSampleFreq);
		int iObsSamps=int(iToneSamps/dSampRatio);
		unsigned long ulObsSamps=int(iSamplesPerSecond*rrRawFile.rbBlock.dScanLen); //# samples in scan
		iPlayChan=4;

		ulPlayTime=0;

		for(int iCurSample=0; iCurSample<iNumSamples; iCurSample++) { //one cycle of waveform
			dTime=double(iCurSample)/iNumSamples;
			dValue+=sin(TWO_PI*dTime);

			rrRawFile.rbBlock.GetSample(iPlayChan,ulPlayTime,1,rsSample);
			dValue*=rsSample.dPwr*dAmp;
			
			if(iBitsPerSample==16) ((short*)lprgcBuffer)[iCurSample]=short(dValue);
			else lprgcBuffer[iCurSample]=ClipAudioSample(dValue);

			ulPlayTime++;
			if(ulPlayTime>=rrRawFile.rbBlock.ulObsTimes) {
				ulPlayTime=0;
				audioPause();
			}
		}

		audioWrite(lprgcBuffer,iNumSamples*iBytesPerSample);
	}

	delete lprgcBuffer;

	return 0;
}
*/
